package com.ngmaster.socket;

import java.util.HashMap;
import java.util.Map;

import com.ngmaster.apiserver.config.SocketConfig;
import com.ngmaster.socket.handler.*;
import com.ngmaster.socket.message.*;

import io.netty.buffer.ByteBuf;

/**
 * 消息工厂，用来创建消息
 * */
public class MessageManager {

    private static MessageManager instance = new MessageManager();
    /** 客户端或者web平台发送过来的指令 */
    private static Map<CmdType, MessageHandler> handlerMap = new HashMap<>();
    /** 服务器返回给客户端或者web平台的消息处理器 */
    private static Map<CmdType, MessageHandler> resHandlerMap = new HashMap<>();

    private SocketConfig socketConfig;

    public static final MessageManager getInstance() {
        return instance;
    }

    public void init(SocketConfig socketConfig) {
        this.socketConfig = socketConfig;

        handlerMap.put(CmdType.GainDeviceId, new GainDeviceIdHandler());
        handlerMap.put(CmdType.HeartBeat, new HeartBeatHandler());
        handlerMap.put(CmdType.BindPricing, new ReceiveBindPricingHandler());

        handlerMap.put(CmdType.ScreenClose, new ReceiveCloseScreenHandler());
        handlerMap.put(CmdType.ScreenOpen, new ReceiveOpenScreenHandler());
        handlerMap.put(CmdType.Shutdown, new ReceiveShowdownHandler());
        handlerMap.put(CmdType.Startup, new ReceiveStartupHandler());
        handlerMap.put(CmdType.ForceWash, new ReceiveForceWashHandler());
        handlerMap.put(CmdType.AddMoney, new ReceiveAddMoneyHandler());
        handlerMap.put(CmdType.SubMoney, new ReceiveSubMoneyHandler());
        handlerMap.put(CmdType.SyncWater, new SyncWaterHandler());
        handlerMap.put(CmdType.SyncTime, new ReceiveSyncUsedTimeHandler());
        handlerMap.put(CmdType.SyncWorkStatus, new SyncWorkStatusHandler());
        handlerMap.put(CmdType.UpdateFilter, new ReceiveFilterUpdateHandler());
        handlerMap.put(CmdType.SwitchBillModel, new ReceiveSwitchBillModelHandler());
        handlerMap.put(CmdType.WipeData, new ReceiveWipeDataHandler());
        handlerMap.put(CmdType.UpdateHeartbeatInterval, new ReceiveUpdateHeartbeatIntervalHandler());

        handlerMap.put(CmdType.RWPumpWorkTime, new ReceiveReadOrModifyPumpWorkTimeHandler());
        handlerMap.put(CmdType.RWWashTime, new ReceiveReadOrModifyWashTimeHandler());
        handlerMap.put(CmdType.RWFixWashTime, new ReceiveReadOrModifyWashFixedTimeHandler());
        handlerMap.put(CmdType.RWServiceTime, new ReceiveReadOrModifyServiceTimeHandler());
        handlerMap.put(CmdType.RWReWashTime, new ReceiveReadOrModifyReWashTimeMessageHandler());

        handlerMap.put(CmdType.ReadIccid, new ReadIccidFromDeviceHandler());
        handlerMap.put(CmdType.OneWaterOfTime, new ReadOrModifyOneWaterOfTimeMessageHandler());
    }

    public ProtocolMessage createMessage(ByteBuf byteBuf) {
        ProtocolMessage message = null;

        byte cmd = byteBuf.getByte(ProtocolMessage.icCidLength);
        CmdType cmdType = CmdType.get(cmd);
        if (cmdType != null) {
            switch (cmdType) {
                case GainDeviceId:
                    message = new GainDeviceIdMessage();
                    break;
                case HeartBeat: // 心跳
                    message = new HeartbeatMessage();
                    break;
                case BindPricing:
                    message = new BindPricingMessage();
                    break;
                case ScreenClose:
                    message = new ScreenCloseMessage();
                    break;
                case ScreenOpen:
                    message = new ScreenOpenMessage();
                    break;
                case Shutdown:
                    message = new ShutdownMessage();
                    break;
                case Startup:
                    message = new StartUpMessage();
                    break;
                case ForceWash:
                    message = new ForceWashMessage();
                    break;
                case AddMoney:
                    message = new AddMoneyMessage();
                    break;
                case SubMoney:
                    message = new SubMoneyMessage();
                    break;
                case SyncWater:
                    message = new SyncWaterMessage();
                    break;
                case SyncTime:
                    message = new SyncDayMessage();
                    break;
                case SyncWorkStatus:
                    message = new SyncWorkStatusMessage();
                    break;
                case UpdateFilter:
                    message = new FilterUpdateMessage();
                    break;
                case SwitchBillModel:
                    message = new SwitchBillModelMessage();
                    break;
                case WipeData:
                    message = new WipeDataMessage();
                    break;
                case UpdateHostPort:
                    break;
                case UpdateHeartbeatInterval:
                    message = new UpdateHeartbeatIntervalMessage();
                    break;
                case RWPumpWorkTime:
                    message = new PumpWorkTimeMessage();
                    break;
                case RWWashTime:
                    message = new ReadOrModifyWashTimeMessage();
                    break;
                case RWFixWashTime:
                    message = new ReadOrModifyWashFixedTimeMessage();
                    break;
                case RWServiceTime:
                    message = new ReadOrModifyServiceTimeMessage();
                    break;
                case RWReWashTime:
                    message = new ReadOrModifyReWashTimeMessage();
                    break;
                case ReadIccid:
                    message = new ReadIccidFromDeviceMessage();
                    break;
                case OneWaterOfTime:
                    message = new ReadOrModifyOneWaterOfTimeMessage();
                    break;
            }
        }
        if (message != null) {
            ByteArray byteArray = new ByteArray();
            int readableBytes = byteBuf.readableBytes();
            byte[] src = new byte[readableBytes];
            byteBuf.readBytes(src);
            System.arraycopy(src, 0, byteArray.getBytes(), 0, src.length);
            message.setByteArray(byteArray);
            message.deserialize();
            message.convertByteImeiToHex();
        }

        return message;
    }

    public MessageHandler getReqHandler(CmdType cmdType) {
        return handlerMap.get(cmdType);
    }

    public boolean handleMessage(ProtocolMessage protocolMessage) {
        boolean result = false;
        MessageHandler handler = getReqHandler(CmdType.get(protocolMessage.getCmd()));
        if (handler != null) {
            result = handler.handleMessage(protocolMessage);
        }
        return result;
    }

    public SocketConfig getSocketConfig() {
        return socketConfig;
    }

    public void setSocketConfig(SocketConfig socketConfig) {
        this.socketConfig = socketConfig;
    }
}
